package com.gitee.wsl.unit.angle.ext

import com.gitee.wsl.unit.angle.AngleUnit
import com.gitee.wsl.unit.angle.toDegrees


/**
 * Computes the linear interpolation of two angles in the range [-180, +180] degrees according to a specified
 * fractional amount. The fractional amount is interpreted as a relative proportion of the two angles, where 0.0
 * indicates the first angle, 0.5 indicates an angle half way between the two angles, and 1.0 indicates the second
 * angle.
 * <br>
 * The result of this method is undefined if the amount is outside the range [0, 1].
 *
 * @param amount the fractional proportion of the two angles in the range [0, 1]
 * @param angle1 the first angle in degrees
 * @param angle2 the second angle in degrees
 *
 * @return the interpolated angle in the range [-180, +180] degrees
 */

fun AngleUnit.Companion.interpolateAngle180(amount: Double, angle1: AngleUnit, angle2: AngleUnit): AngleUnit {
    // Normalize the two angles to the range [-180, +180].
    var normalizedAngle1 = normalizeAngle180(angle1.degrees)
    var normalizedAngle2 = normalizeAngle180(angle2.degrees)

    // If the shortest arc between the two angles crosses the -180/+180 degree boundary, add 360 degrees to the
    // smaller of the two angles then interpolate.
    if (normalizedAngle1 - normalizedAngle2 > 180) normalizedAngle2 += 360.0
    else if (normalizedAngle1 - normalizedAngle2 < -180) normalizedAngle1 += 360.0

    // Linearly interpolate between the two angles then normalize the interpolated result. Normalizing the result is
    // necessary when we have added 360 degrees to either angle in order to interpolate along the shortest arc.
    val angle = (1 - amount) * normalizedAngle1 + amount * normalizedAngle2
    return normalizeAngle180(angle).toDegrees()
}

/**
 * Computes the linear interpolation of two angles in the range [0, 360] degrees according to a specified fractional
 * amount. The fractional amount is interpreted as a relative proportion of the two angles, where 0.0 indicates the
 * first angle, 0.5 indicates an angle half way between the two angles, and 1.0 indicates the second angle.
 * <br>
 * The result of this method is undefined if the amount is outside the range [0, 1].
 *
 * @param amount the fractional proportion of the two angles in the range [0, 1]
 * @param angle1 the first angle
 * @param angle2 the second angle
 *
 * @return the interpolated angle in the range [0, 360] degrees
 */

fun AngleUnit.Companion.interpolateAngle360(amount: Double, angle1: AngleUnit, angle2: AngleUnit): AngleUnit {
    // Normalize the two angles to the range [-180, +180].
    var normalizedAngle1 = normalizeAngle180(angle1.degrees)
    var normalizedAngle2 = normalizeAngle180(angle2.degrees)

    // If the shortest arc between the two angles crosses the -180/+180 degree boundary, add 360 degrees to the
    // smaller of the two angles then interpolate.
    if (normalizedAngle1 - normalizedAngle2 > 180) normalizedAngle2 += 360.0
    else if (normalizedAngle1 - normalizedAngle2 < -180) normalizedAngle1 += 360.0

    // Linearly interpolate between the two angles then normalize the interpolated result. Normalizing the result is
    // necessary when we have added 360 degrees to either angle in order to interpolate along the shortest arc.
    val angle = (1 - amount) * normalizedAngle1 + amount * normalizedAngle2
    return normalizeAngle360(angle).toDegrees()
}